package com.gmall.data.service;

import com.gmall.data.api.UserActionSequenceQueryService;
import com.gmall.data.pojo.LogBean;
import com.gmall.data.pojo.RuleAtomicParam;
import com.gmall.data.pojo.RuleParam;
import com.gmall.data.utils.RuleUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.flink.api.common.state.ListState;

import java.util.List;

/**
 *  用户行为次序类条件查询服务实现（在state中查询）
 */
@Slf4j
public class UserActionSequenceQueryServiceImpl implements UserActionSequenceQueryService {

    ListState<LogBean> eventState;

    public UserActionSequenceQueryServiceImpl(ListState<LogBean> eventState){
        this.eventState = eventState;
    }

    /**
     * 行为序列： A(p1=v2,p3=v8) B(p6=v9,p7=v7)  C()
     * 意味着用户要依顺序做过上面的事件
     * 查询规则条件中的行为序列条件是否满足
     * 会将查询到的最大匹配步骤，set回 ruleParam对象中
     * @param deviceId
     * @param ruleParam 规则参数对象
     * @return 条件是否成立
     * @throws Exception
     */
    @Override
    public boolean queryActionSequence(String deviceId, RuleParam ruleParam) throws Exception {

        // 1.取出状态(事件明细)以及规则
        Iterable<LogBean> logBeans = eventState.get();
        List<RuleAtomicParam> ruleParams = ruleParam.getUserActionSequenceParams();

        // 2.调用helper统计实际匹配的最大步骤号
        int maxStep = queryActionSequenceHelper(logBeans, ruleParams);

        // 3.将这个maxStep丢回规则参数对象，以便本服务的调用者可以根据需要获取到这个最大匹配步骤号
        ruleParam.setUserActionSequenceQueriedMaxStep(ruleParam.getUserActionSequenceQueriedMaxStep() + maxStep);

        // 4.然后判断整个序列条件是否满足：真实最大匹配步骤是否等于条件的步骤数
        return maxStep == ruleParams.size();
    }

    /**
     * 序列匹配
     * @param events
     * @param userActionSequenceParams
     * @return
     */
    private int queryActionSequenceHelper(Iterable<LogBean> events, List<RuleAtomicParam> userActionSequenceParams) {
        int maxStep = 0;
        for (LogBean event : events) {
            if (RuleUtil.logBeanMathParam(event, userActionSequenceParams.get(maxStep))) {
                maxStep++;
            }
            if (maxStep == userActionSequenceParams.size()) break;
        }
        return maxStep;
    }
}
